package rubix.data
{
	import flash.events.EventDispatcher;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	
	import rubix.events.CubeEvent;
	import rubix.view.RubixView;

	[Event(name="cubeRotated", type="rubix.events.CubeEvent")]
	[Event(name="cubeHighlighted", type="rubix.events.CubeEvent")]
	[Event(name="cubeUnHighlighted", type="rubix.events.CubeEvent")]
	public class RubixModel extends EventDispatcher
	{
		public static const ORIGIN:Vector3D=new Vector3D();
		private var _cubes:Vector.<Array>;
		private var _view:RubixView;
		
		public function RubixModel(){
			initModel();
		}
		public function get cubes():Vector.<Array>{
			return _cubes;
		}
		private function initModel():void{
			_cubes=new Vector.<Array>();
			var cx:int,cy:int,cz:int;
			for (var i:int = 0; i < 27; i++) 
			{
				// Вычисляем и записываем положение кубика
				cx=i%3-1;
				cy=Math.floor(i%9/3)-1;
				cz=Math.floor(i/9)-1;
				_cubes.push([cx,cy,cz]);
			}
			
		}
		
		// Служебный метод для работы с orientation.
		// Выявляет индекс значимого элемента ( который != 0)
		private function getValuable(orientation:Array):Number{
			if(orientation==null) return Number.NaN;
			var valuable:int=0;
			for(valuable;valuable<orientation.length;valuable++){ 
				if(orientation[valuable]!=0)break;
			}
			return valuable;
		}
		// Метод для подсветки грани куба
		public function highlightSide(orientation:Array=null):void
		{
			var valuable:Number=getValuable(orientation);
			_cubes.forEach(function(item:Array,ind:int,...rest):void{
				if(!isNaN(valuable)&&orientation&&(item[valuable]==orientation[valuable])){
					dispatchEvent(new CubeEvent(CubeEvent.CUBE_HIGHLIGHTED,ind));
				}else{
					dispatchEvent(new CubeEvent(CubeEvent.CUBE_UNHIGHLIGHTED,ind));
				}
			});
		}
		
		// Вращение грани
		public function rotateSide(orientation:Array,degrees:Number=90):void{
			
			var valuable:int=getValuable(orientation);
			var mtrx:Matrix3D=new Matrix3D();
			var axis:Vector3D=new Vector3D(orientation[0],orientation[1],orientation[2]);
			mtrx.appendRotation(degrees,axis,ORIGIN);
			_cubes.forEach(function(item:Array,ind:int,...rest):void{
					// По положению кубиков определяем только нужные кубики
					if( item[valuable]==orientation[valuable]){
						updateItemPosition(item,mtrx);
						dispatchEvent(new CubeEvent(CubeEvent.CUBE_ROTATED,ind,degrees,axis));
					}
			});
			
			
		}
		// Метод для обновления положения кубика в кубе
		private function updateItemPosition(pos:Array,matrix:Matrix3D):void
		{
			var pv:Vector3D=new Vector3D(pos[0],pos[1],pos[2]);
			pv=matrix.transformVector(pv);
			pos[0]=pv.x;
			pos[1]=pv.y;
			pos[2]=pv.z;
		}
		
		
		
	}
}